package mmap

import (
	"os"
	"syscall"
	"unsafe"
)

type sliceHeader struct {
	Data uintptr
	Len  int
	Cap  int
}

// mmap 创建内存
func mmap(fd int, offset int64, size int) ([]byte, error) {
	var h syscall.Handle
	var errno error

	if fd != 0 {
		h, errno = syscall.CreateFileMapping(fd, nil,
			syscall.PAGE_READONLY, uint32(fsize>>32), uint32(fsize)&0xffffffff, nil)
	} else {
		h, errno = syscall.CreateFileMapping(syscall.InvalidHandle, nil,
			syscall.PAGE_EXECUTE_READWRITE, uint32(size>>32), uint32(size)&0xffffffff, nil)
	}
	if h == 0 {
		return nil, os.NewSyscallError("CreateFileMapping", errno)
	}

	addr, errno := syscall.MapViewOfFile(h,
		syscall.FILE_MAP_READ|syscall.FILE_MAP_WRITE|syscall.FILE_MAP_EXECUTE,
		uint32(offset>>32), uint32(offset)&0xffffffff, uintptr(size))
	if addr == 0 {
		return nil, os.NewSyscallError("MapViewOfFile", errno)
	}

	if err := syscall.CloseHandle(syscall.Handle(h)); err != nil {
		return nil, os.NewSyscallError("CloseHandle", err)
	}

	var header sliceHeader
	header.Data = addr
	header.Len = size
	header.Cap = size
	b := *(*[]byte)(unsafe.Pointer(&header))

	return b, nil
}

// munmap 销毁内存
func munmap(b []byte) error {
	addr := (uintptr)(unsafe.Pointer(&b[0]))
	if err := syscall.UnmapViewOfFile(addr); err != nil {
		return os.NewSyscallError("UnmapViewOfFile", err)
	}
	return nil
}
